#   /**
#   * Copyright (c) 2022 Beijing Jiaotong University
#   * PhotLab is licensed under [Open Source License].
#   * You can use this software according to the terms and conditions of the [Open Source License].
#   * You may obtain a copy of [Open Source License] at: [https://open.source.license/]
#   *
#   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
#   * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
#   * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#   *
#   * See the [Open Source License] for more details.
#   */
#   /**
#   * Author: Zheng Wang
#   * Created: Dec. 14, 2022
#   * Supported by: National Key Research and Development Program of China
#   */

import logging
import time
from phot_engine.computing_graph import Vertex
from phot_engine.computing_graph import Edge
from phot_engine.computing_graph import Port
from phot_engine.computing_graph import Parameter
from phot_engine.computing_graph import PhotLabGraph
from phot_engine.globals import TaskPriority
from phot_engine.globals import TaskStatus
from phot_engine.globals import VerificationError
from phot_engine.core import SimulationTask
from phot_engine.utils import universal_function

__all__ = ["def_component_parameter", "def_component", "def_edge", "generate_simulation_task"]


def def_component_parameter(py_phot_name_list: list,
                            data_type_list: list,
                            value_list: list,
                            unit_list: list,
                            phot_unit_list: list) -> list:
    """
        用于生成光组件参数列表
        To generate photo-electron component parameter list
    :param py_phot_name_list:
    :param data_type_list:
    :param value_list:
    :param unit_list:
    :param phot_unit_list:
    :return:
    """
    parameter_list = []
    list_length = len(py_phot_name_list)
    if not universal_function.check_all_list_length_is_same(
            list_length,
            py_phot_name_list,
            data_type_list,
            value_list,
            unit_list,
            phot_unit_list):
        raise VerificationError("Please check input lists' length, they should have same length.")
    for i in range(0, list_length):
        parameter_dict = {
            "pyPhotName": py_phot_name_list[i],
            "dataType": data_type_list[i],
            "value": value_list[i],
            "unit": unit_list[i],
            "photUnit": phot_unit_list[i]
        }
        parameter = Parameter(source_data=parameter_dict)
        logging.debug("[functional]:generated parameter {}".format(parameter))
        parameter_list.append(parameter)
    return parameter_list


def def_component(
        component_id: str,
        phot_class_name: str,
        phot_func_name: str,
        parameter_list: list,
        is_class: bool,
        device: str = "CPU",
        is_analyzer: bool = False) -> Vertex:
    """
    用于定义光电子组件
    To define a photo-electron component
    :param component_id:
    :param phot_class_name:
    :param phot_func_name:
    :param parameter_list:
    :param is_class:
    :param device:
    :param is_analyzer:
    :return:
    """
    if not is_class:
        """
            如果不是类,而是函数式调用则phot_lib_class_name == phot_lib_func_name
        """
        vertex = Vertex(
            vertex_id=component_id,
            phot_lib_class_name=phot_func_name,
            phot_lib_func_name=phot_func_name,
            is_analyzer=is_analyzer,
            parallel_computing_method=device,
            vertex_param_list=parameter_list
        )
    else:
        vertex = Vertex(
            vertex_id=component_id,
            phot_lib_class_name=phot_class_name,
            phot_lib_func_name=phot_func_name,
            is_analyzer=is_analyzer,
            parallel_computing_method=device,
            vertex_param_list=parameter_list
        )
    return vertex


def def_edge(source_component: Vertex,
             source_port: int,
             destination_component: Vertex,
             destination_port: int,
             signal_type: str = "") -> Edge:
    """
    In order to define an edge between one photo-electron component and another one
    :param source_component:
    :param source_port:
    :param destination_component:
    :param destination_port:
    :param signal_type:
    :return:
    """
    if not (isinstance(source_component, Vertex) and isinstance(destination_component, Vertex)):
        # validate component data type
        raise VerificationError("source_component and destination_component should be Vertex type,not: {},{}"
                                .format(type(source_component),
                                        type(destination_component)))
    if not (isinstance(source_port, int) and isinstance(destination_port, int)):
        raise VerificationError("source_port and destination_port should be int type,not: {},{}"
                                .format(type(source_port),
                                        type(destination_port)))
    source_vertex_id = source_component.get_vertex_id()
    destination_vertex_id = destination_component.get_vertex_id()
    source_port = Port(vertex_id=source_vertex_id, port_id=str(source_port))
    destination_port = Port(vertex_id=destination_vertex_id, port_id=str(destination_port))
    edge = Edge(source_port=source_port, destination_port=destination_port, signal_type=signal_type)
    return edge


def __generate_vertex_dict(component_list: list):
    """
        generate vertex dict from component list
    :param component_list: [Vertex,Vertex,...]
    :return: {"":Vertex,"":Vertex}
    """
    vertex_dict = {}
    for component in component_list:
        if isinstance(component, Vertex):
            vertex_dict[component.get_vertex_id()] = component
    return vertex_dict


def __generate_phot_lab_graph(vertex_dict: dict, edge_list: list) -> PhotLabGraph:
    if not (isinstance(vertex_dict, dict) and isinstance(edge_list, list)):
        raise VerificationError("vertex_dict,edge_list should be dict, list type,not:{},{}"
                                .format(type(vertex_dict),
                                        type(edge_list)))
    phot_lab_graph = PhotLabGraph(vertex_dict, edge_list)
    return phot_lab_graph


def generate_simulation_task(task_id: str,
                             priority: TaskPriority,
                             component_list: list,
                             edge_list: list) -> SimulationTask:
    """

    :param task_id:
    :param priority:
    :param component_list:
    :param edge_list:
    :return:
    """
    vertex_dict = __generate_vertex_dict(component_list)
    phot_lab_graph = __generate_phot_lab_graph(vertex_dict=vertex_dict, edge_list=edge_list)
    simulation_task = SimulationTask(task_id=task_id,
                                     starting_executing_time=time.time(),
                                     priority=priority,
                                     graph=phot_lab_graph,
                                     global_parameter=None)
    simulation_task.set_task_status(TaskStatus.TASK_CREATING)
    logging.info("[functional]: Simulation task has generated.")
    return simulation_task


if __name__ == '__main__':
    pass
